#pragma once

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <list>
#include <iostream>

#include <unistd.h>

#ifdef __WIN32__

#include <winsock2.h>
#include <WS2tcpip.h>

#else

#define INVALID_SOCKET -1
#include <sys/socket.h>
#include <sys/types.h>

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>

#include <sys/time.h>
#include <sys/wait.h>

#endif

#include "Dispatch.h"

#define MAX_CONNECTIONS 10
#define TEXT_PORT 6716
#define FILE_PORT 6715
#define CORRUPT_CLIENT_THRESHOLD 10

class Server {
public:
	Server(unsigned int, unsigned int, char* const*, bool);
	~Server( void );
	
	// Main run function for the server.
	void run();
	
	// Can be set to daemon mode so can be run in the background.
	bool daemon;
	
	// Print only if not in daemon mode
	inline void ifprintf(const char *message, ...) { if(!daemon) { va_list args; va_start(args, message); vfprintf(stdout, message, args); va_end(args); } }
	
private:
	
	typedef struct {
		std::string username;
		unsigned int socket;
		
		// Keeps track of the number of corrupt messages
		// the server recieves from the client. Too many
		// will result in the server dropping the client.
		unsigned int corrupt;
		
	} ClientConnection;
	
	struct sockaddr_in my_addr;
	
	// To listening socket to which clients initially connect.
	int connectfd;
	
	// File Descriptor set for client connections
	fd_set clients_set;
	// List of client connections
	std::list<ClientConnection*> clients;
	// Maximum file descriptor. Used in multiplexing I/O
	int max_fd;
	
	unsigned int maxConnects;
	unsigned int messagesPort;
	unsigned int transferPort;
	
	/* Responsible for taking a socket and creating
	 * a new ClientConnection.
	 ***************************************************/
	void acceptConnection( int socket );
	
	/* Takes a Dispatch pointer and sends it to all
	 * the clients in the servers client list (clients)
	 * Will exclude the ClientConnection if specified
	 ***************************************************/
	void notifyClients( Dispatch *dispatch, ClientConnection* exclude = NULL );
	
	/* Disconnects client. Closes socket, and notifies
	 * all other clients using the most appropriate
	 * DispatchFlag (See Dispatch.h).
	 * DOES NOT REMOVE CLIENT FROM clients LIST!
	 ***************************************************/
	void disconnectClient( ClientConnection* client );
	
	/* Sets the maximum File Descriptor from the list
	 * of clients currently connected to the server
	 ***************************************************/
	void setMaxFD(void);
	
	/* Various forms of initializing the server.
	 * If parameters are not specified, defaults are
	 * used instead. See top of Server.h
	 ***************************************************/
	void init(void);
	void init(unsigned int max);
	void init(unsigned int max, unsigned int port1);
	void init(unsigned int max, unsigned int port1, unsigned int port2);
	
public:
	
	/* Returns a comma seperated list of users (usernames)
	 * excluding a particular client if specified.
	 ****************************************************/
	std::string listUsers( ClientConnection *ignore = NULL );
};
